#!/bin/bash
#author: xieziqiang
#email: xie.zi.qiang@outlook.com

# https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.14.3-linux-x86_64.tar.gz
# https://artifacts.elastic.co/downloads/logstash/logstash-7.17.22-linux-x86_64.tar.gz
## you need two files in current dir. logstash-7.17.22-linux-x86_64.tar.gz and ca.pem
## and if LS_BEAT_SSL=true,then you need upload LS_BEAT_CERT.
set -euo pipefail
#****** vars *********#
LS_VERSION="8.14.3"
LS_INSTALL_PATH="/usr/local"
LS_USER="logstash"
LS_DATA_PATH="/data/logstash-data"
LS_LOGS_PATH="/data/logstash-logs"
LS_JVM_XMS="512m"   # default 1g
LS_JVM_XMX="512m"   # default 1g

LS_BEAT_SSL="true" # true or false
#    you can use elasticsearch-certutil to generate cert
LS_BEAT_CERT="/root/logstash.pem"
LS_BEAT_KEY="/root/logstash.key"

LS_BEAT_CERT_NAME="${LS_BEAT_CERT##*/}"
LS_BEAT_KEY_NAME="${LS_BEAT_KEY##*/}"

#******* elasticsearch config ***********#
ES_HOSTS='["https://10.0.0.50:9200","https://10.0.0.51:9200","https://10.0.0.52:9200"]'

ES_SSL="true" # true or false
ES_LS_USER="elastic"
ES_LS_PASSWD="xzq1428"
ES_CACERT="/root/ca.pem"
ES_CACERT_NAME="${ES_CACERT##*/}"
#****** functions *********#
color() {
    local message="$1"
    local status="$2"
    local terminal_width
    terminal_width=$(tput cols)
    local middle_column=$(( terminal_width / 2))
    local SETCOLOR_SUCCESS="\033[1;32m"  # 绿色
    local SETCOLOR_FAILURE="\033[1;31m"  # 红色
    local SETCOLOR_WARNING="\033[1;33m"  # 黄色
    local SETCOLOR_NORMAL="\033[0m"      # 重置颜色
    printf '%s\n\033[%sG' "${message}"  "${middle_column}"
    # Print the status message
    printf "["
    case ${status} in
        success|0)
            echo -en  "${SETCOLOR_SUCCESS}  OK  "
            ;;
        failure|1)
            echo -en  "${SETCOLOR_FAILURE}FAILED"
            ;;
        *)
            echo -en "${SETCOLOR_WARNING}WARNING"
            ;;
    esac
    echo -e "${SETCOLOR_NORMAL}]"
}

judge_current_user () {
    if [ "$(id -u)" = "0" ];then
        color "current user is administrator" 0
    else
        color "current user is not administrator" 1
        exit
    fi
}

create_user () {
    if ! id "$1" &> /dev/null;then
        useradd -r -M -s /sbin/nologin "$1" \
        && color "$1 user is created." 0 \
        || { color "$1 user create failed.";exit; }
    else
        color "$1 user is existed." 2
    fi
}

create_dir () {
    local i
    for i in "$@";do
        if [ ! -d "$i" ];then
            mkdir -pv "$i" && color "$i dir is created" 0
        else
            color "$i dir is existed." 2
        fi
    done
}

process_file () {

    if [ "${LS_BEAT_SSL}" = "true" ];then
        if ! [ -e "$LS_BEAT_CERT" ];then 
            color "$LS_BEAT_CERT is not exist." 1
            exit
        fi
    fi

    if [ "${ES_SSL}" = "true" ];then
        if ! [ -e "$ES_CACERT" ];then 
            color "$ES_CACERT is not exist." 1
            exit
        fi
    fi

    if [ ! -e "logstash-${LS_VERSION}-linux-x86_64.tar.gz" ];then
        color "current directory dont exist logstash-${LS_VERSION}-linux-x86_64.tar.gz" 1
        exit
    fi

    tar -xvf "logstash-${LS_VERSION}-linux-x86_64.tar.gz" -C "${LS_INSTALL_PATH}"
    ln -nfs  ${LS_INSTALL_PATH}/logstash-${LS_VERSION} ${LS_INSTALL_PATH}/logstash
    create_dir ${LS_DATA_PATH} ${LS_LOGS_PATH} ${LS_INSTALL_PATH}/logstash/config/conf.d
}

set_certs () {
    if [ "${LS_BEAT_SSL}" = "true" ];then
        \cp "${LS_BEAT_CERT}" ${LS_INSTALL_PATH}/logstash/config/
        \cp "${LS_BEAT_KEY}" ${LS_INSTALL_PATH}/logstash/config/
        chmod 400 "${LS_INSTALL_PATH}/logstash/config/${LS_BEAT_CERT_NAME}" "${LS_INSTALL_PATH}/logstash/config/${LS_BEAT_KEY_NAME}"
    fi

    if [ "${ES_SSL}" = "true" ];then
        \cp  "${ES_CACERT}"  ${LS_INSTALL_PATH}/logstash/config/
        chmod 400 "${LS_INSTALL_PATH}/logstash/config/${ES_CACERT_NAME}"
    fi
}

set_logstash_configfile () {

    \cp ${LS_INSTALL_PATH}/logstash/config/logstash.yml{,.bak}
    cat > ${LS_INSTALL_PATH}/logstash/config/logstash.yml<<EOF
path.data: ${LS_DATA_PATH}
path.logs: ${LS_LOGS_PATH}
EOF

    \cp ${LS_INSTALL_PATH}/logstash/config/pipelines.yml{,.bak}
    cat > ${LS_INSTALL_PATH}/logstash/config/pipelines.yml<<EOF
- pipeline.id: main
  path.config: "${LS_INSTALL_PATH}/logstash/config/conf.d/*.conf"
EOF

    sed -i  "/^-Xms/c -Xms${LS_JVM_XMS}" ${LS_INSTALL_PATH}/logstash/config/jvm.options
    sed -i  "/^-Xmx/c -Xmx${LS_JVM_XMX}" ${LS_INSTALL_PATH}/logstash/config/jvm.options

cat > ${LS_INSTALL_PATH}/logstash/config/conf.d/logstash.conf <<EOF
input {
  beats {
    port => 5044
    ssl => ${LS_BEAT_SSL}
    ssl_certificate_authorities => ["${LS_INSTALL_PATH}/logstash/config/${ES_CACERT_NAME}"]
    ssl_certificate => "${LS_INSTALL_PATH}/logstash/config/${LS_BEAT_CERT_NAME}"
    ssl_key => "${LS_INSTALL_PATH}/logstash/config/${LS_BEAT_KEY_NAME}"
  }
}

output {
  elasticsearch {
    hosts => ${ES_HOSTS}
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    ssl => ${ES_SSL}
    cacert => "${LS_INSTALL_PATH}/logstash/config/${ES_CACERT_NAME}"
    user => "${ES_LS_USER}"
    password => "${ES_LS_PASSWD}"
  }
}
EOF

    if [ "${LS_BEAT_SSL}" = "false" ];then
        sed -i \
        -e '/^    ssl_certificate_authorities => /s/^/#/g' \
        -e '/^    ssl_certificate => /s/^/#/g' \
        -e '/^    ssl_key => /s/^/#/g' \
        ${LS_INSTALL_PATH}/logstash/config/conf.d/logstash.conf 
    fi

    if [ "${ES_SSL}" = "false" ];then
        sed -i  \
        -e '/^    cacert =>/s/^/#/g' \
        -e '/^    user =>/s/^/#/g' \
        -e '/^    password =>/s/^/#/g' \
        ${LS_INSTALL_PATH}/logstash/config/conf.d/logstash.conf
    fi

    chown -HR ${LS_USER}:${LS_USER} ${LS_DATA_PATH} ${LS_LOGS_PATH}  ${LS_INSTALL_PATH}/logstash 
}

init_logstash_service () {
    cat > /lib/systemd/system/logstash.service<<EOF
[Unit]
Description=logstash

[Service]
Type=simple
User=${LS_USER}
Group=${LS_USER}
# Load env vars from /etc/default/ and /etc/sysconfig/ if they exist.
# Prefixing the path with '-' makes it try to load, but if the file doesn't
# exist, it continues onward.
# EnvironmentFile=-/etc/default/logstash
# EnvironmentFile=-/etc/sysconfig/logstash
Environment=LS_HOME="${LS_INSTALL_PATH}/logstash"
Environment=LS_SETTINGS_DIR="${LS_INSTALL_PATH}/logstash/config"
Environment=LS_PIDFILE="${LS_INSTALL_PATH}/logstash/logstash.pid"
Environment=LS_USER="${LS_USER}"
Environment=LS_GROUP="${LS_USER}"
Environment=LS_GC_LOG_FILE="${LS_INSTALL_PATH}/logstash/gc.log"
Environment=LS_OPEN_FILES="16384"
Environment=LS_NICE="19"
Environment=SERVICE_NAME="logstash"
Environment=SERVICE_DESCRIPTION="logstash"

ExecStart=${LS_INSTALL_PATH}/logstash/bin/logstash "--path.settings" "${LS_INSTALL_PATH}/logstash/config"
Restart=always
WorkingDirectory=/
Nice=19
LimitNOFILE=16384

# When stopping, how long to wait before giving up and sending SIGKILL?
# Keep in mind that SIGKILL on a process can cause data loss.
TimeoutStopSec=infinity

[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable logstash.service
    systemctl start logstash.service \
    && color "logstash start sucess!" 0 \
    || { color "logstash start fail." 1; exit; }
}

main () {
    if ! [[ ${LS_BEAT_SSL} =~ ^true$|^false$ ]];then
        color "ES_SSL vars set is wrong,check script." 1
        exit
    fi

    if ! [[ ${ES_SSL} =~ ^true$|^false$ ]];then
        color "ES_SSL vars set is wrong,check script." 1
        exit
    fi
    judge_current_user
    create_user ${LS_USER}
    process_file
    set_certs
    set_logstash_configfile
    init_logstash_service
}

main